package one

import (
	"fmt"
	"time"

	"gddgame.cc/galaxy/common/service/lobby"
	"gddgame.cc/galaxy/utils"
	"gddgame.cc/galaxy/utils/def"
	"gddgame.cc/galaxy/utils/serialize/msgpack"
)

// 匹配机制：先到先组
type one struct {
	def.Serialize
}
type oneComputer struct {
	buckets []*bucket
}
type bucket struct {
	client *lobby.Client
	time   *time.Time
}

func (computer *oneComputer) init() {
	computer.buckets = make([]*bucket, 0)
}

func (computer *oneComputer) Refresh(q *lobby.Queue) ([]*lobby.Client, map[string]interface{}) {
	computer.init()
	index := 0
	for e := q.Clients.Front(); e != nil; e = e.Next() {
		clients, c := computer.Add(e.Value.(*lobby.Client), index)
		if clients != nil {
			return clients, c
		}
		index++
	}
	return nil, nil
}

func (computer *oneComputer) Add(client *lobby.Client, index int) ([]*lobby.Client, map[string]interface{}) {
	for _, bucket := range computer.buckets {
		fmt.Println("add")
		return []*lobby.Client{bucket.client, client}, bucket.client.Options
	}
	var tt *time.Time
	if value, ok := client.Options["seconds"]; ok {
		t := client.Time.Add(time.Duration(utils.ToInt(value)) * time.Second)
		tt = &t
	}
	computer.buckets = append(computer.buckets, &bucket{
		client: client,
		time:   tt,
	})
	return nil, nil
}

func (computer *oneComputer) Timeout() ([]*lobby.Client, map[string]interface{}) {
	t := time.Now()
	for index, bucket := range computer.buckets {
		if bucket.time != nil && bucket.time.Before(t) {
			if len(computer.buckets) == 1 {
				computer.buckets = computer.buckets[:0]
			} else if index == 0 {
				computer.buckets = computer.buckets[1:]
			} else if index == len(computer.buckets)-1 {
				computer.buckets = computer.buckets[0:index]
			} else {
				computer.buckets = append(computer.buckets[:index], computer.buckets[index+1:]...)
			}
			return []*lobby.Client{bucket.client}, bucket.client.Options
		}
	}
	return nil, nil
}

var (
	Default *one
)

func init() {
	Default = &one{
		Serialize: msgpack.Msgpack(true),
	}
}

func (p *one) ID() string {
	return "one"
}

func (p *one) GetComputer(channel string) lobby.Computer {
	return &oneComputer{}
}

func (p *one) Channel(users map[string]string, options map[string]interface{}) (string, []byte, error) {
	mode := options["mode"]
	if mode == nil {
		return "", nil, fmt.Errorf("Empty options:mode")
	}

	channel := utils.ToString(mode)
	payload, err := p.Serialize.Marshal(options)
	return channel, payload, err
}
func (p *one) Parse(channel string, payload []byte) map[string]interface{} {
	data := make(map[string]interface{})
	_ = p.Serialize.Unmarshal(payload, &data)
	return data
}
func (p *one) Need(users map[string]string, options map[string]interface{}) bool {
	people := options["people"]
	if people == nil {
		return true
	}

	if utils.ToInt(people) != len(users) {
		return true
	} else {
		return false
	}
}
